home *** CD-ROM | disk | FTP | other *** search
- Subject: v22i040: NN Newsreader, release 6.4, Part05/21
- Newsgroups: comp.sources.unix
- Approved: rsalz@uunet.UU.NET
- X-Checksum-Snefru: 6cc7a4e0 72b69816 29afbd42 7cfb04a3
-
- Submitted-by: "Kim F. Storm" <storm@texas.dk>
- Posting-number: Volume 22, Issue 40
- Archive-name: nn6.4/part05
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # Contents: man/nngrab.1 newsrc.c sequence.c
- # Wrapped by storm@texas.dk on Sun May 6 18:19:25 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 5 (of 22)."'
- if test -f 'man/nngrab.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'man/nngrab.1'\"
- else
- echo shar: Extracting \"'man/nngrab.1'\" \(1616 characters\)
- sed "s/^X//" >'man/nngrab.1' <<'END_OF_FILE'
- X.TH NNGRAB 1 "Release 6.4"
- X.UC 4
- X.SH NAME
- Xnngrab \- news retrieval by keyword (nn)
- X.SH SYNOPSIS
- X.B nngrab
- X.I keyword
- X.SH DESCRIPTION
- X.I nngrab
- Xinvokes \fInn\fP
- Xon all USENET articles whose subject (or keyword) field(s)
- Xcontain an instance of \fIkeyword\fP. \fInngrab\fP is a fast
- Xequivalent for:
- X.sp 0.5v
- X nn -mxX -s/\fIkeyword\fP all
- X.LP
- XFor example,
- X.sp 0.5v
- X nngrab tesla
- X.sp 0.5v
- Xwill retrieve items concerning Nikola Tesla.
- X.LP
- XKeyword case is ignored, and the \fIkeyword\fP can be a regular
- Xexpressions (escaped to avoid conflicts with the shell). For example,
- X.sp 0.5v
- X nngrab "n.*tesla"
- X.LP
- XThe range of search includes all newsgroups on the system,
- Xincluding ones which are unsubscribed.
- X.SH FILES
- X.DT
- X.ta \w'$db/subjects'u+3m
- X.\"ta 0 16
- X$db/subjects subject database
- X.DT
- X.SH SEE ALSO
- Xnn(1), nnspew(8), egrep(1)
- X.SH NOTES
- X\fInngrap\fP \fIcan be\fP much faster than the equivalent command
- Xshown above, if the tertiary news subject
- Xdatabase generated by the \fInnspew\fP(8) daemon exists. To enable
- Xthe faster operation, \fInnspew\fP must be executed regularly by cron.
- X.LP
- X\fInngrab\fP uses \fIegrep\fP(1) to scan the subject database, so
- Xif you are not running \fIfast\fP egrep (GNU-style) this is all for
- Xnaught.
- X.LP
- X\fInngrab\fP will use a subject database generated by \fInnspew\fP
- Xindependent of its age. Thus, if you stop running \fInnspew\fP,
- Xremember to remove the subjects file as well.
- X.SH BUGS
- XUnder version 6.4, search of the "Keywords:" field is not supported.
- X.br
- XSearch on name is not possible either.
- X.SH AUTHOR
- XJames A. Woods, NASA Ames Research Center
- X.br
- XE-mail: jaw@ames.arc.nasa.gov
- END_OF_FILE
- if test 1616 -ne `wc -c <'man/nngrab.1'`; then
- echo shar: \"'man/nngrab.1'\" unpacked with wrong size!
- fi
- # end of 'man/nngrab.1'
- fi
- if test -f 'newsrc.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'newsrc.c'\"
- else
- echo shar: Extracting \"'newsrc.c'\" \(34671 characters\)
- sed "s/^X//" >'newsrc.c' <<'END_OF_FILE'
- X/*
- X * (c) Copyright 1990, Kim Fabricius Storm. All rights reserved.
- X *
- X * .newsrc parsing and update.
- X */
- X
- X#include "config.h"
- X#include "options.h"
- X#include "regexp.h"
- X#include "term.h"
- X#include "articles.h"
- X
- X#define TR(arg) printf arg
- X
- Ximport char *news_lib_directory, *db_directory;
- Ximport char *pname;
- X
- Ximport int verbose;
- Ximport int silent;
- X
- Xexport int keep_rc_backup = 1;
- Xexport char *bak_suffix = ".bak";
- X
- Xexport int no_update = 0;
- Xexport int use_selections = 1;
- Xexport int quick_unread_count = 1; /* make a quick count of unread art. */
- Xexport int newsrc_update_freq = 1; /* how often to write .newsrc */
- Xexport char *newsrc_file = NULL;
- X
- X#define RCX_NEVER 0 /* ignore missing groups */
- X#define RCX_HEAD 1 /* prepend missing groups to .newsrc when read */
- X#define RCX_TAIL 2 /* append missing groups to .newsrc when read */
- X#define RCX_TIME 3 /* append NEW groups as they arrive */
- X#define RCX_TIME_CONF 4 /* append NEW groups with confirmation */
- X#define RCX_RNLAST 5 /* .rnlast compatible functionality */
- X
- Xexport int new_group_action = RCX_TIME; /* append new groups to .newsrc */
- Xexport int keep_unsubscribed = 1; /* keep unsubscribed groups in .newsrc */
- Xexport int keep_unsub_long = 0; /* keep unread in unsubscribed groups */
- X
- Xexport int tidy_newsrc = 0; /* remove obsolete groups from .newsrc */
- X
- Xexport int auto_junk_seen = 1; /* junk seen articles ... */
- Xexport int conf_junk_seen = 0; /* ... if confirmed by user ... */
- Xexport int retain_seen_status = 0; /* ... or remember seen articles. */
- X
- Xexport long unread_articles; /* estimate of unread articles */
- Xexport int unread_groups;
- X
- Xexport group_header *rc_sequence = NULL;
- X
- Xstatic char *sel_path = NULL;
- X
- X
- X/* delimitors on newsrc lines */
- X
- X#define RC_SUBSCR ':' /* subscription to group */
- X#define RC_UNSUBSCR '!' /* no subscription to group */
- X
- X#define RC_DELIM ',' /* separator on rc lines */
- X#define RC_RANGE '-' /* range */
- X
- X/* delimitors on select lines */
- X
- X#define SEL_RANGE '-' /* range */
- X#define SEL_SELECT ',' /* following articles are selected */
- X#define SEL_LEAVE '+' /* following articles are left over */
- X#define SEL_SEEN ';' /* following articles are seen */
- X#define SEL_UNREAD '~' /* in digests */
- X#define SEL_DIGEST '(' /* start digest list */
- X#define SEL_END_DIGEST ')' /* end digest list */
- X#define SEL_NEW '&' /* new group (group.name&nnn) */
- X
- X#define END_OF_LIST 10000000L /* Greater than any article number */
- X
- X/* line buffers */
- X
- X#define RC_LINE_MAX 8192
- X
- Xstatic char rcbuf[RC_LINE_MAX];
- Xstatic char selbuf[RC_LINE_MAX];
- X
- Xstatic group_header *rc_seq_tail = NULL;
- X
- Xstatic int newsrc_update_count = 0, select_update_count = 0;
- X
- X#define DM_NEWSRC 0
- X#define DM_SELECT 1
- X#define DM_ORIG_NEWSRC 2
- X#define DM_ORIG_SELECT 3
- X
- Xstatic dump_file(path, mode)
- Xchar *path;
- Xint mode;
- X{
- X FILE *f = NULL;
- X register group_header *gh;
- X char *line;
- X
- X Loop_Groups_Newsrc(gh) {
- X switch (mode) {
- X case DM_NEWSRC:
- X if (tidy_newsrc) {
- X if ((gh->master_flag & M_VALID) == 0)
- X continue;
- X if (!keep_unsubscribed && (gh->group_flag & G_UNSUBSCRIBED))
- X continue;
- X }
- X line = gh->newsrc_line;
- X break;
- X case DM_SELECT:
- X if (tidy_newsrc && (gh->master_flag & M_VALID) == 0) continue;
- X if (gh->group_flag & G_UNSUBSCRIBED) continue;
- X line = gh->select_line;
- X break;
- X case DM_ORIG_NEWSRC:
- X line = gh->newsrc_orig;
- X break;
- X case DM_ORIG_SELECT:
- X line = gh->select_orig;
- X break;
- X }
- X if (line == NULL) continue;
- X if (f == NULL)
- X f = open_file(path, OPEN_CREATE|MUST_EXIST);
- X fputs(line, f);
- X }
- X if (f != NULL) fclose(f);
- X}
- X
- X
- Xstatic dump_newsrc()
- X{
- X char bak[FILENAME];
- X static int first = 1;
- X
- X if (no_update) return;
- X if (++newsrc_update_count < newsrc_update_freq) return;
- X
- X if (first && keep_rc_backup) {
- X sprintf(bak, "%s%s", newsrc_file, bak_suffix);
- X dump_file(bak, DM_ORIG_NEWSRC);
- X first = 0;
- X }
- X
- X dump_file(newsrc_file, DM_NEWSRC);
- X
- X newsrc_update_count = 0;
- X}
- X
- Xstatic dump_select()
- X{
- X char bak[FILENAME];
- X static int first = 1;
- X
- X if (no_update) return;
- X if (++select_update_count < newsrc_update_freq) return;
- X
- X if (first && keep_rc_backup) {
- X sprintf(bak, "%s%s", sel_path, bak_suffix);
- X dump_file(bak, DM_ORIG_SELECT);
- X first = 0;
- X }
- X
- X dump_file(sel_path, DM_SELECT);
- X
- X select_update_count = 0;
- X}
- X
- X#define RN_LAST_GROUP_READ 0
- X#define RN_LAST_TIME_RUN 1
- X#define RN_LAST_ACTIVE_SIZE 2
- X#define RN_LAST_CREATION_TIME 3
- X#define RN_LAST_NEW_GROUP 4
- X#define RN_ACTIVE_TIMES_OFFSET 5
- X
- X#define MAX_RNLAST_LINE 6
- X
- Xstatic char *rnlast_line[MAX_RNLAST_LINE];
- Xstatic char *rnlast_path;
- X
- Xstatic time_t get_last_new()
- X{
- X FILE *lf = NULL;
- X char buf[FILENAME];
- X register int i;
- X
- X if (new_group_action == RCX_RNLAST) {
- X rnlast_path = home_relative(".rnlast");
- X lf = open_file(rnlast_path, OPEN_READ);
- X if (lf == NULL) goto no_file;
- X
- X for (i = 0; i < MAX_RNLAST_LINE; i++) {
- X if (fgets(buf, FILENAME, lf) == NULL) break;
- X rnlast_line[i] = copy_str(buf);
- X }
- X if (i != MAX_RNLAST_LINE) {
- X printf(".rnlast only supported with active.times patches\n");
- X sleep(3);
- X new_group_action = RCX_TIME_CONF;
- X goto no_file;
- X }
- X fclose(lf);
- X return (time_t)atol(rnlast_line[RN_LAST_CREATION_TIME]);
- X }
- X
- X lf = open_file(relative(nn_directory, "LAST"), OPEN_READ);
- X if (lf == NULL) goto no_file;
- X if (fgets(buf, FILENAME, lf) == NULL) goto no_file;
- X
- X fclose(lf);
- X return (time_t)atol(buf);
- X
- X no_file:
- X if (lf != NULL) fclose(lf);
- X return (time_t)(-1);
- X}
- X
- Xstatic update_last_new(lastg)
- Xgroup_header *lastg;
- X{
- X FILE *lf = NULL;
- X register int i;
- X struct stat st;
- X
- X if (new_group_action == RCX_RNLAST) {
- X lf = open_file(rnlast_path, OPEN_CREATE|MUST_EXIST);
- X fputs(rnlast_line[RN_LAST_GROUP_READ], lf); /* as good as any */
- X fprintf(lf, "%ld\n", (long)cur_time()); /* RN_LAST_TIME_RUN */
- X fprintf(lf, "%ld\n", (long)master.last_size); /* RN_LAST_ACTIVE_SIZE */
- X
- X fprintf(lf, "%ld\n", (long)lastg->creation_time); /* RN_LAST_CREATION_TIME */
- X fprintf(lf, "%s\n",lastg->group_name); /* RN_LAST_NEW_GROUP */
- X
- X if (stat(relative(news_lib_directory, "active.times"), &st) == 0)
- X fprintf(lf, "%ld\n", (long)st.st_size);
- X else /* can't be perfect -- don't update */
- X fputs(rnlast_line[RN_ACTIVE_TIMES_OFFSET], lf);
- X for (i = 0; i < MAX_RNLAST_LINE; i++) freeobj(rnlast_line[i]);
- X freeobj(rnlast_path);
- X } else {
- X lf = open_file(relative(nn_directory, "LAST"), OPEN_CREATE|MUST_EXIST);
- X fprintf(lf, "%ld\n%s\n", (long)lastg->creation_time, lastg->group_name);
- X }
- X
- X fclose(lf);
- X}
- X
- Xstatic article_number get_last_article(gh)
- Xgroup_header *gh;
- X{
- X register char *line;
- X
- X if ((line = gh->newsrc_line) == NULL) return -1;
- X
- X line += gh->group_name_length+1;
- X while (*line && isspace(*line)) line++;
- X if (*line == NUL) return -1;
- X
- X if (line[0] == '1') {
- X if (line[1] == RC_RANGE)
- X return atol(line+2);
- X if (!isdigit(line[1])) return 1;
- X }
- X return 0;
- X}
- X
- X
- Xvisit_rc_file()
- X{
- X FILE *rc, *sel;
- X register group_header *gh;
- X int subscr;
- X register char *bp;
- X register int c;
- X char bak[FILENAME];
- X time_t last_new_group = 0, rc_age, newsrc_age;
- X group_header *last_new_gh = NULL;
- X
- X if (newsrc_file == NULL)
- X newsrc_file = home_relative(".newsrc");
- X
- X sel_path = mk_file_name(nn_directory, "select");
- X
- X Loop_Groups_Header(gh) {
- X gh->newsrc_line = NULL;
- X gh->newsrc_orig = NULL;
- X gh->select_line = NULL;
- X gh->select_orig = NULL;
- X }
- X
- X if (rc_age = file_exist(relative(nn_directory, "rc"), (char *)NULL)) {
- X if (who_am_i != I_AM_NN)
- X user_error("A release 6.3 rc file exists. Run nn to upgrade");
- X
- X sprintf(bak, "%s/upgrade_rc", lib_directory);
- X
- X if ((newsrc_age = file_exist(newsrc_file, (char *)NULL)) == 0) {
- X display_file("adm.upgrade1", CLEAR_DISPLAY);
- X } else {
- X if (rc_age + 60 > newsrc_age) {
- X /* rc file is newest (or .newsrc does not exist) */
- X display_file("adm.upgrade2", CLEAR_DISPLAY);
- X prompt("Convert rc file to .newsrc now? ");
- X if (yes(1) <= 0) nn_exit(0);
- X } else {
- X /* .newsrc file is newest */
- X display_file("adm.upgrade3", CLEAR_DISPLAY);
- X prompt("Use current .newsrc file? ");
- X if (yes(1) > 0) {
- X strcat(bak, " n");
- X } else {
- X display_file("adm.upgrade4", CLEAR_DISPLAY);
- X prompt("Convert rc file to .newsrc? ");
- X if (yes(1) <= 0) {
- X printf("Then you will have to upgrade manually\n");
- X nn_exit(0);
- X }
- X }
- X }
- X }
- X
- X printf("\r\n\n");
- X system(bak);
- X any_key(prompt_line);
- X }
- X
- X rc = open_file(newsrc_file, OPEN_READ);
- X if (rc == NULL) goto new_user;
- X
- X while (fgets(rcbuf, RC_LINE_MAX, rc) != NULL) {
- X gh = NULL;
- X subscr = 0;
- X for (bp = rcbuf; (c = *bp); bp++) {
- X if (isspace(c)) break; /* not a valid line */
- X
- X if (c == RC_UNSUBSCR || c == RC_SUBSCR) {
- X subscr = (c == RC_SUBSCR);
- X *bp = NUL;
- X gh = lookup(rcbuf);
- X if (gh == NULL) {
- X gh = newobj(group_header, 1);
- X gh->group_name = copy_str(rcbuf); /* invalid group! */
- X }
- X *bp = c;
- X break;
- X }
- X }
- X
- X if (gh == NULL) {
- X gh = newobj(group_header, 1);
- X gh->group_flag |= G_FAKED;
- X gh->master_flag |= M_VALID;
- X }
- X
- X if (rc_seq_tail == NULL)
- X rc_sequence = rc_seq_tail = gh;
- X else {
- X rc_seq_tail->newsrc_seq = gh;
- X rc_seq_tail = gh;
- X }
- X
- X gh->newsrc_orig = gh->newsrc_line = copy_str(rcbuf);
- X if (gh->group_flag & G_FAKED)
- X gh->group_name = gh->newsrc_line;
- X else
- X if (!subscr)
- X gh->group_flag |= G_UNSUBSCRIBED;
- X }
- X fclose(rc);
- X
- X new_user:
- X rc = NULL;
- X Loop_Groups_Header(gh) {
- X if (gh->master_flag & M_IGNORE_GROUP) continue;
- X if (gh->group_flag & G_UNSUBSCRIBED) continue;
- X if (gh->newsrc_line == NULL) {
- X char buf[FILENAME];
- X
- X /* NEW GROUP - ADD TO NEWSRC AS APPROPRIATE */
- X
- X if (new_group_action == RCX_NEVER) {
- X gh->group_flag |= G_DONE; /* will not enter sequence */
- X continue;
- X }
- X
- X switch (new_group_action) {
- X case RCX_NEVER:
- X /* no not add new groups */
- X gh->group_flag |= G_DONE;
- X continue;
- X
- X case RCX_HEAD:
- X /* insert at top */
- X gh->newsrc_seq = rc_sequence;
- X rc_sequence = gh;
- X break;
- X
- X
- X case RCX_TIME:
- X case RCX_TIME_CONF:
- X case RCX_RNLAST:
- X if (last_new_group == 0)
- X last_new_group = get_last_new();
- X
- X if (gh->creation_time <= last_new_group) {
- X /* old groups not in .newsrc are unsubscribed */
- X gh->group_flag |= G_UNSUBSCRIBED;
- X continue;
- X }
- X
- X if (last_new_gh == NULL || last_new_gh->creation_time <= gh->creation_time)
- X last_new_gh = gh;
- X
- X if (new_group_action != RCX_TIME) {
- X printf("\nNew group: %s -- append to .newsrc? (y)");
- X if (yes(0) <= 0) continue;
- X }
- X sprintf(buf, "%s:\n", gh->group_name);
- X /* to avoid fooling the LAST mechanism, we must fake */
- X /* that the group was also in the original .newsrc */
- X
- X gh->newsrc_orig = gh->newsrc_line = copy_str(buf);
- X newsrc_update_count++;
- X
- X /* fall thru */
- X
- X case RCX_TAIL:
- X /* insert at bottom */
- X if (rc_seq_tail == NULL)
- X rc_sequence = rc_seq_tail = gh;
- X else {
- X rc_seq_tail->newsrc_seq = gh;
- X rc_seq_tail = gh;
- X }
- X break;
- X }
- X
- X gh->last_article = -1;
- X } else
- X gh->last_article = get_last_article(gh);
- X
- X if (gh->last_article < 0) {
- X gh->group_flag |= G_NEW;
- X gh->last_article = gh->first_db_article - 1;
- X } else
- X if (gh->first_db_article > gh->last_article)
- X gh->last_article = gh->first_db_article - 1;
- X
- X if (gh->last_article < 0) gh->last_article = 0;
- X gh->first_article = gh->last_article;
- X }
- X
- X if (rc_seq_tail)
- X rc_seq_tail->newsrc_seq = NULL;
- X
- X if (last_new_gh != NULL)
- X update_last_new(last_new_gh);
- X
- X if (!use_selections) return;
- X
- X sel = open_file(sel_path, OPEN_READ);
- X if (sel == NULL) return;
- X
- X while (fgets(selbuf, RC_LINE_MAX, sel) != NULL) {
- X gh = NULL;
- X for (bp = selbuf; (c = *bp); bp++)
- X if (c == SP || c == SEL_NEW) break;
- X
- X if (c == NUL) continue;
- X *bp = NUL;
- X gh = lookup(selbuf);
- X if (gh == NULL) continue;
- X *bp = c;
- X if (c == SEL_NEW) gh->group_flag |= G_NEW;
- X gh->select_orig = gh->select_line = copy_str(selbuf);
- X }
- X fclose(sel);
- X}
- X
- X/*
- X * prepare to use newsrc & select information for a specific group
- X */
- X
- Xstatic char *rc_p; /* pointer into newsrc_line */
- Xstatic article_number rc_min; /* current newsrc range min */
- Xstatic article_number rc_max; /* current newsrc range max */
- Xstatic char rc_delim; /* delimiter character */
- X
- Xstatic char *sel_p; /* pointer into select_line */
- Xstatic char *sel_initp; /* rc_p after initialization */
- Xstatic article_number sel_min; /* current select range min */
- Xstatic article_number sel_max; /* current select range max */
- Xstatic article_number sel_digest; /* current digest */
- Xstatic attr_type sel_type; /* current select range type */
- Xstatic char sel_delim; /* delimiter character */
- X
- X
- Xuse_newsrc(gh, use_orig)
- Xregister group_header *gh;
- Xint use_orig;
- X{
- X/* TR( ("===%s===", gh->group_name) );*/
- X
- X if (use_orig) {
- X rc_p = gh->newsrc_orig;
- X sel_p = gh->select_orig;
- X } else {
- X rc_p = gh->newsrc_line;
- X sel_p = gh->select_line;
- X }
- X
- X if (rc_p == NULL) {
- X rc_min = rc_max = END_OF_LIST;
- X } else {
- X rc_min = rc_max = -1;
- X rc_delim = SP;
- X rc_p += gh->group_name_length + 1;
- X }
- X
- X sel_digest = 0;
- X if (sel_p == NULL) {
- X sel_min = sel_max = END_OF_LIST;
- X } else {
- X sel_p += gh->group_name_length + 1;
- X sel_min = sel_max = -1;
- X sel_delim = SP;
- X }
- X}
- X/*
- X#define TRC(wh) TR( ("r%d>%-8.8s< %ld %ld %ld %c\n", wh, p ? p : "***", n, rc_min, rc_max, rc_delim) )
- X#define TSEL(wh) TR( ("s%d>%-8.8s< %ld %ld %ld %c\n", wh, p ? p : "***", n, sel_min, sel_max, sel_delim) )
- X*/
- X#define TRC(wh)
- X#define TSEL(wh)
- X
- Xattr_type test_article(ah)
- Xregister article_header *ah;
- X{
- X register char *p;
- X register int c;
- X register int32 n = ah->a_number, x;
- X
- X while (n > rc_max) {
- X /* get next interval from newsrc line */
- X rc_min = -1;
- X x = 0;
- X p = rc_p;
- X TRC(1);
- X
- X if (*p == RC_DELIM) p++;
- X if (*p == NUL || *p == NL)
- X rc_min = rc_max = END_OF_LIST;
- X else {
- X for ( ; (c = *p) && c != RC_DELIM && c != NL; p++) {
- X if (c == RC_RANGE) {
- X if (rc_min < 0)
- X rc_min = x;
- X else
- X msg("syntax error in rc file");
- X x = 0;
- X continue;
- X }
- X
- X if (isascii(*p) && isdigit(*p))
- X x = x*10 + c - '0';
- X }
- X rc_max = x;
- X if (rc_min < 0) rc_min = x;
- X rc_p = p;
- X }
- X }
- X TRC(2);
- X
- X if (n >= rc_min && n <= rc_max) return A_READ;
- X
- X p = sel_p;
- X if (sel_digest != 0) {
- X if (n == sel_digest && (ah->flag & A_DIGEST)) {
- X if (*sel_p == SEL_END_DIGEST) return A_READ;
- X n = ah->fpos;
- X } else {
- X if (n < sel_digest) return 0;
- X while (*p && *p++ != SEL_END_DIGEST);
- X sel_digest = 0;
- X sel_min = sel_max = -1;
- X }
- X }
- X
- X while (n > sel_max) {
- X sel_min = -1;
- X sel_type = A_SELECT;
- X x = 0;
- X TSEL(3);
- X
- X for (;;) {
- X switch (*p) {
- X case SEL_SELECT:
- X sel_type = A_SELECT;
- X p++;
- X continue;
- X case SEL_LEAVE:
- X sel_type = A_LEAVE;
- X p++;
- X continue;
- X case SEL_SEEN:
- X sel_type = A_SEEN;
- X p++;
- X continue;
- X case SEL_UNREAD:
- X sel_type = 0;
- X p++;
- X continue;
- X case SEL_DIGEST:
- X while (*p && *p++ != SEL_END_DIGEST);
- X continue;
- X case SEL_END_DIGEST:
- X if (sel_digest) {
- X if (sel_digest == ah->a_number) {
- X sel_p = p;
- X return A_READ;
- X }
- X sel_digest = 0;
- X }
- X p++;
- X sel_type = A_SELECT;
- X continue;
- X default:
- X break;
- X }
- X break;
- X }
- X
- X if (*p == NUL || *p == NL) {
- X sel_min = sel_max = END_OF_LIST;
- X break;
- X }
- X
- X for ( ; c = *p ; p++ ) {
- X switch (c) {
- X case '0':
- X case '1':
- X case '2':
- X case '3':
- X case '4':
- X case '5':
- X case '6':
- X case '7':
- X case '8':
- X case '9':
- X x = x*10 + c - '0';
- X continue;
- X
- X case SEL_SELECT:
- X case SEL_LEAVE:
- X case SEL_SEEN:
- X case SEL_UNREAD:
- X break;
- X
- X case SEL_RANGE:
- X if (sel_min < 0)
- X sel_min = x;
- X else
- X msg("syntax error in sel file");
- X x = 0;
- X continue;
- X
- X case SEL_DIGEST:
- X n = ah->a_number;
- X if (n > x) {
- X while (*p && (*p++ != SEL_END_DIGEST));
- X x = -1;
- X break;
- X }
- X p++;
- X sel_digest = x;
- X if (n < sel_digest) {
- X sel_p = p;
- X return 0;
- X }
- X n = ah->fpos;
- X x = -1;
- X break;
- X
- X case NL:
- X if (sel_digest == 0) break;
- X /* fall thru */
- X case SEL_END_DIGEST:
- X if (sel_digest == ah->a_number) {
- X sel_p = p;
- X return (ah->fpos == x) ? sel_type : A_READ;
- X }
- X sel_digest = 0;
- X x = -1;
- X break;
- X }
- X break;
- X }
- X sel_max = x;
- X if (sel_min < 0) sel_min = x;
- X sel_p = p;
- X }
- X
- X if (n >= sel_min && n <= sel_max) return sel_type;
- X
- X if (sel_digest) return A_READ; /* only read articles are not listed */
- X
- X return 0; /* unread, unseen, unselected */
- X}
- X
- X/*
- X * We only mark the articles that should remain unread
- X */
- X
- X/*VARARGS*/
- Xstatic append(va_alist)
- Xva_dcl
- X{
- X int x;
- X register char *p;
- X char **pp, *fmt;
- X use_vararg;
- X
- X start_vararg;
- X x = va_arg1(int);
- X pp = x ? &sel_p : &rc_p;
- X p = *pp;
- X if (p > (x ? &selbuf[RC_LINE_MAX - 16] : &rcbuf[RC_LINE_MAX - 16])) {
- X msg("%s line too long", x ? "select" : ".newsrc");
- X end_vararg;
- X return;
- X }
- X fmt = va_arg2(char *);
- X vsprintf(p, fmt, va_args3toN);
- X end_vararg;
- X
- X while (*p) p++;
- X *p = NL;
- X p[1] = NUL;
- X *pp = p;
- X}
- X
- Xstatic append_range(pp, delim, rmin, rmax)
- Xint pp;
- Xchar delim;
- Xarticle_number rmin, rmax;
- X{
- X if (rmin == rmax)
- X append(pp, "%c%ld", delim, (long)rmin);
- X else
- X append(pp, "%c%ld%c%ld", delim, (long)rmin, RC_RANGE, (long)rmax);
- X}
- X
- Xstatic int32 mark_counter;
- X
- Xstatic begin_rc_update(gh)
- Xregister group_header *gh;
- X{
- X add_unread(gh, -1);
- X mark_counter = 0;
- X
- X rc_p = rcbuf;
- X rc_min = 1;
- X append(0, "%s%c", gh->group_name,
- X gh->group_flag & G_UNSUBSCRIBED ? RC_UNSUBSCR : RC_SUBSCR);
- X rc_delim = SP;
- X sel_p = selbuf;
- X sel_min = 0;
- X sel_max = 0;
- X sel_digest = 0;
- X sel_delim = SP;
- X append(1, "%s%c", gh->group_name,
- X (gh->group_flag & G_NEW) ? SEL_NEW : SP);
- X /* sel_initp == sep_p => empty list */
- X sel_initp = (gh->group_flag & G_NEW) ? NULL : sel_p;
- X}
- X
- Xstatic end_rc_update(gh)
- Xregister group_header *gh;
- X{
- X if (rc_min <= gh->last_db_article)
- X append_range(0, rc_delim, rc_min, gh->last_db_article);
- X
- X if (gh->newsrc_line != NULL && strcmp(rcbuf, gh->newsrc_line)) {
- X if (gh->newsrc_orig != gh->newsrc_line)
- X freeobj(gh->newsrc_line);
- X gh->newsrc_line = NULL;
- X }
- X
- X if (gh->newsrc_line == NULL) {
- X gh->newsrc_line = copy_str(rcbuf);
- X dump_newsrc();
- X }
- X
- X if (sel_digest)
- X append(1, "%c", SEL_END_DIGEST);
- X else
- X if (sel_min)
- X append_range(1, sel_delim, sel_min, sel_max);
- X
- X if (gh->select_line) {
- X if (strcmp(selbuf, gh->select_line) == 0) goto out;
- X } else
- X if (sel_p == sel_initp) goto out;
- X
- X if (gh->select_line && gh->select_orig != gh->select_line)
- X freeobj(gh->select_line);
- X
- X gh->select_line = (sel_p == sel_initp) ? NULL : copy_str(selbuf);
- X dump_select();
- X
- X out:
- X if ((gh->last_article = get_last_article(gh)) < 0)
- X gh->last_article = 0;
- X
- X gh->group_flag |= G_READ; /* should not call update_group again */
- X if (mark_counter > 0) {
- X gh->unread_count = mark_counter;
- X add_unread(gh, 0);
- X }
- X}
- X
- Xstatic mark_article(ah, how)
- Xregister article_header *ah;
- Xattr_type how;
- X{
- X register article_number anum;
- X char delim;
- X
- X switch (how) {
- X case A_SELECT:
- X delim = SEL_SELECT;
- X break;
- X case A_SEEN:
- X delim = SEL_SEEN;
- X break;
- X case A_LEAVE:
- X case A_LEAVE_NEXT:
- X delim = SEL_LEAVE;
- X break;
- X case 0:
- X delim = SEL_UNREAD;
- X break;
- X }
- X
- X mark_counter++;
- X anum = ah->a_number;
- X
- X if (rc_min < anum) {
- X append_range(0, rc_delim, rc_min, anum - 1);
- X rc_delim = RC_DELIM;
- X
- X if ((ah->flag & A_DIGEST) == 0
- X && sel_min && delim == sel_delim && sel_max == (rc_min - 1))
- X sel_max = anum - 1; /* expand select range over read articles */
- X }
- X rc_min = anum + 1;
- X
- X if (ah->flag & A_DIGEST) {
- X if (sel_digest != anum) {
- X if (sel_digest) {
- X append(1, "%c", SEL_END_DIGEST);
- X } else
- X if (sel_min) {
- X append_range(1, sel_delim, sel_min, sel_max);
- X sel_min = 0;
- X }
- X append(1, "%c%ld%c", SEL_SELECT, (long)anum, SEL_DIGEST);
- X sel_digest = anum;
- X }
- X
- X append(1, "%c%ld", delim, (long)ah->fpos);
- X return;
- X }
- X
- X if (sel_digest) {
- X append(1, "%c", SEL_END_DIGEST);
- X sel_digest = 0;
- X }
- X
- X if (sel_min) {
- X if (delim != sel_delim || delim == SEL_UNREAD) {
- X append_range(1, sel_delim, sel_min, sel_max);
- X sel_delim = delim;
- X if (delim == SEL_UNREAD)
- X sel_min = 0;
- X else
- X sel_min = anum;
- X } else
- X sel_max = anum;
- X } else
- X if (delim != SEL_UNREAD) {
- X sel_min = sel_max = anum;
- X sel_delim = delim;
- X }
- X}
- X
- Xflush_newsrc()
- X{
- X newsrc_update_freq = 0;
- X if (select_update_count) dump_select();
- X if (newsrc_update_count) dump_newsrc();
- X}
- X
- Xrestore_bak()
- X{
- X if (no_update)
- X return 1;
- X
- X prompt("Are you sure? ");
- X if (!yes(1)) return 0;
- X
- X dump_file(newsrc_file, DM_ORIG_NEWSRC);
- X
- X prompt("Restore selections? ");
- X if (yes(1)) dump_file(sel_path, DM_ORIG_SELECT);
- X
- X no_update = 1; /* so current group is not updated */
- X return 1;
- X}
- X
- X/*
- X * Update .newsrc for one group.
- X * sort_articles(0) MUST HAVE BEEN CALLED BEFORE USE.
- X */
- X
- Xupdate_rc(gh)
- Xregister group_header *gh;
- X{
- X register article_header *ah, **ahp;
- X register article_number art;
- X register int junk_seen = 0;
- X
- X if (gh->group_flag & (G_FOLDER | G_FAKED)) return;
- X
- X begin_rc_update(gh);
- X
- X for (ahp = articles, art = 0; art < n_articles; ahp++, art++) {
- X ah = *ahp;
- X if (ah->a_group != NULL && ah->a_group != gh) continue;
- X
- X switch (ah->attr) {
- X case A_READ:
- X case A_KILL:
- X continue;
- X
- X case A_LEAVE:
- X case A_LEAVE_NEXT:
- X case A_SELECT:
- X mark_article(ah, ah->attr);
- X continue;
- X
- X case A_SEEN:
- X if (junk_seen == 0) {
- X junk_seen = -1;
- X if (auto_junk_seen) {
- X if (conf_junk_seen) {
- X prompt("\1Junk seen articles\1 ");
- X if (yes(0) > 0) junk_seen = 1;
- X } else
- X junk_seen = 1;
- X }
- X }
- X if (junk_seen > 0) continue;
- X mark_article(ah, (attr_type)(retain_seen_status ? A_SEEN : 0));
- X continue;
- X
- X case A_AUTO_SELECT:
- X default:
- X mark_article(ah, (attr_type)0);
- X continue;
- X }
- X }
- X
- X end_rc_update(gh);
- X}
- X
- Xupdate_rc_all(gh, unsub)
- Xregister group_header *gh;
- Xint unsub;
- X{
- X if (unsub) {
- X gh->group_flag &= ~G_NEW;
- X gh->group_flag |= G_UNSUBSCRIBED;
- X
- X if (!keep_unsubscribed) {
- X add_unread(gh, -1);
- X if (gh->newsrc_line != NULL && gh->newsrc_orig != gh->newsrc_line)
- X freeobj(gh->newsrc_line);
- X gh->newsrc_line = NULL;
- X return;
- X }
- X
- X if (keep_unsub_long) {
- X update_rc(gh);
- X return;
- X }
- X }
- X
- X begin_rc_update(gh);
- X end_rc_update(gh);
- X}
- X
- Xadd_to_newsrc(gh)
- Xgroup_header *gh;
- X{
- X gh->group_flag &= ~G_UNSUBSCRIBED;
- X
- X if (gh->newsrc_seq != NULL || gh == rc_seq_tail) {
- X update_rc(gh);
- X return;
- X }
- X
- X rc_seq_tail->newsrc_seq = gh;
- X rc_seq_tail = gh;
- X if (gh->last_db_article > 0)
- X sprintf(rcbuf, "%s: %s%ld\n", gh->group_name,
- X gh->last_db_article > 1 ? "1-" : "",
- X (long)gh->last_db_article);
- X else
- X sprintf(rcbuf, "%s:\n", gh->group_name);
- X gh->newsrc_line = copy_str(rcbuf);
- X dump_newsrc();
- X}
- X
- Xint32 restore_rc(gh, last)
- Xregister group_header *gh;
- Xarticle_number last;
- X{
- X register article_number *numtab, n;
- X register attr_type *attrtab, attr;
- X register int32 at, atmax;
- X article_header ahdr;
- X int32 count;
- X
- X if (last > gh->last_db_article) return 0;
- X
- X if (gh->unread_count <= 0) {
- X /* no unread articles to account for -- quick update */
- X n = gh->last_db_article; /* fake for end_rc_update */
- X gh->last_db_article = last;
- X begin_rc_update(gh);
- X end_rc_update(gh);
- X gh->last_db_article = n;
- X add_unread(gh, 1); /* not done by end_rc_update bec. mark_counter==0 */
- X return gh->unread_count;
- X }
- X
- X /* there are unread articles in the group */
- X /* we must truncate rc&select lines to retain older unread articles */
- X
- X atmax = at = 0;
- X numtab = NULL;
- X attrtab = NULL;
- X
- X use_newsrc(gh, 0);
- X ahdr.flag = 0;
- X count = gh->unread_count;
- X
- X for (n = gh->last_article + 1; n <= last; n++) {
- X if (rc_min == END_OF_LIST) {
- X /* current & rest is unread */
- X last = n - 1;
- X break;
- X }
- X ahdr.a_number = n;
- X if ((attr = test_article(&ahdr)) == A_READ) continue;
- X if (at >= atmax) {
- X atmax += 100;
- X numtab = resizeobj(numtab, article_number, atmax);
- X attrtab = resizeobj(attrtab, attr_type, atmax);
- X }
- X numtab[at] = n;
- X attrtab[at] = attr;
- X at++;
- X }
- X
- X begin_rc_update(gh);
- X while (--at >= 0) {
- X ahdr.a_number = *numtab++;
- X mark_article(&ahdr, *attrtab++);
- X }
- X for (n = last+1; n <= gh->last_db_article; n++) {
- X ahdr.a_number = n;
- X mark_article(&ahdr, (attr_type)0);
- X }
- X end_rc_update(gh);
- X return gh->unread_count - count;
- X}
- X
- Xrestore_unread(gh)
- Xregister group_header *gh;
- X{
- X if (gh->select_line != gh->select_orig) {
- X if (gh->select_line != NULL) freeobj(gh->select_line);
- X gh->select_line = gh->select_orig;
- X dump_select();
- X }
- X
- X if (gh->newsrc_orig == gh->newsrc_line) return 0;
- X
- X add_unread(gh, -1);
- X if (gh->newsrc_line != NULL) freeobj(gh->newsrc_line);
- X gh->newsrc_line = gh->newsrc_orig;
- X gh->last_article = gh->first_article;
- X dump_newsrc();
- X
- X add_unread(gh, 1);
- X
- X return 1;
- X}
- X
- X
- Xcount_unread_articles()
- X{
- X register group_header *gh;
- X long n;
- X
- X unread_articles = 0;
- X unread_groups = 0;
- X
- X Loop_Groups_Sequence(gh) {
- X gh->unread_count = 0;
- X
- X if (gh->master_flag & M_NO_DIRECTORY) continue;
- X
- X if (gh->last_db_article > gh->last_article) {
- X n = unread_articles;
- X add_unread(gh, 1);
- X }
- X
- X if ((gh->group_flag & G_COUNTED) == 0) continue;
- X if (verbose)
- X printf("%6d %s\n", unread_articles - n, gh->group_name);
- X }
- X}
- X
- X
- Xprt_unread(format)
- Xregister char *format;
- X{
- X if (format == NULL) {
- X printf("No News (is good news)\n");
- X return;
- X }
- X
- X while (*format) {
- X if (*format != '%') {
- X putchar(*format++);
- X continue;
- X }
- X format++;
- X switch (*format++) {
- X case 'u':
- X printf("%ld unread article%s", unread_articles, plural((long)unread_articles));
- X continue;
- X case 'g':
- X printf("%d group%s", unread_groups, plural((long)unread_groups));
- X continue;
- X case 'i':
- X printf(unread_articles == 1 ? "is" : "are");
- X continue;
- X case 'U':
- X printf("%ld", unread_articles);
- X continue;
- X case 'G':
- X printf("%d", unread_groups);
- X continue;
- X }
- X }
- X}
- X
- X
- Xadd_unread(gh, mode)
- Xgroup_header *gh;
- Xint mode; /* +1 => count + add, 0 => gh->unread_count, -1 => subtract */
- X{
- X int32 old_count;
- X article_header ahdr;
- X
- X old_count = gh->unread_count;
- X
- X if (mode == 0) goto add_directly;
- X
- X if (gh->group_flag & G_COUNTED) {
- X unread_articles -= gh->unread_count;
- X unread_groups --;
- X gh->unread_count = 0;
- X gh->group_flag &= ~G_COUNTED;
- X }
- X
- X if (mode < 0) goto out;
- X
- X if (quick_unread_count)
- X gh->unread_count = gh->last_db_article - gh->last_article;
- X else {
- X use_newsrc(gh, 0);
- X ahdr.flag = 0;
- X for (ahdr.a_number = gh->last_article + 1;
- X ahdr.a_number <= gh->last_db_article;
- X ahdr.a_number++) {
- X if (rc_min == END_OF_LIST) {
- X gh->unread_count += gh->last_db_article - ahdr.a_number + 1;
- X break;
- X }
- X if (test_article(&ahdr) != A_READ)
- X gh->unread_count++;
- X }
- X }
- X
- X add_directly:
- X if (gh->unread_count <= 0) {
- X gh->unread_count = 0;
- X goto out;
- X }
- X
- X if (gh->group_flag & G_UNSUBSCRIBED) goto out;
- X
- X unread_articles += gh->unread_count;
- X unread_groups++;
- X gh->group_flag |= G_COUNTED;
- X
- X out:
- X return old_count != gh->unread_count;
- X}
- X
- X/*
- X * nngrep
- X */
- X
- Xstatic int
- X grep_all = 0,
- X grep_new = 0,
- X grep_not_sequence = 0,
- X grep_pending = 0,
- X grep_read = 0,
- X grep_sequence = 0,
- X grep_unsub = 0,
- X grep_long = 0,
- X grep_patterns;
- X
- XOption_Description(grep_options) {
- X 'a', Bool_Option(grep_all),
- X 'i', Bool_Option(grep_not_sequence),
- X 'n', Bool_Option(grep_new),
- X 'p', Bool_Option(grep_pending),
- X 'r', Bool_Option(grep_read),
- X 's', Bool_Option(grep_sequence),
- X 'u', Bool_Option(grep_unsub),
- X 'l', Bool_Option(grep_long),
- X '\0',
- X};
- X
- Xopt_nngrep(argc, argv)
- Xint argc;
- Xchar *argv[];
- X{
- X grep_patterns =
- X parse_options(argc, argv, (char *)NULL, grep_options, " pattern...");
- X}
- X
- Xdo_grep(pat)
- Xchar **pat;
- X{
- X register group_header *gh;
- X register regexp **re;
- X register int i;
- X int header = 1;
- X
- X re = newobj(regexp *, grep_patterns);
- X for (i = 0; i < grep_patterns; i++)
- X re[i] = regcomp(pat[i]);
- X
- X Loop_Groups_Sorted(gh) {
- X if (gh->master_flag & M_IGNORE_GROUP) continue;
- X
- X if (grep_pending && gh->unread_count <= 0) continue;
- X if (grep_read && gh->unread_count > 0) continue;
- X if (grep_sequence && (gh->group_flag & G_SEQUENCE) == 0) continue;
- X if (grep_not_sequence && (gh->group_flag & G_SEQUENCE)) continue;
- X if (grep_new && (gh->group_flag & G_NEW) == 0) continue;
- X if (!grep_all) {
- X if (grep_unsub && (gh->group_flag & G_UNSUBSCRIBED) == 0) continue;
- X if (!grep_unsub && (gh->group_flag & G_UNSUBSCRIBED)) continue;
- X }
- X
- X if (grep_patterns > 0) {
- X for (i = 0; i < grep_patterns; i++)
- X if (regexec(re[i], gh->group_name)) break;
- X if (i == grep_patterns) continue;
- X }
- X
- X if (grep_long) {
- X if (header)
- X printf("SUBSCR NEW UNREAD SEQUENCE GROUP\n");
- X header = 0;
- X
- X printf(" %s %s ",
- X (gh->group_flag & G_UNSUBSCRIBED) ? "no " : "yes",
- X (gh->group_flag & G_NEW) ? "yes" : "no ");
- X
- X if (gh->unread_count > 0)
- X printf("%6d ", gh->unread_count);
- X else
- X printf(" ");
- X if (gh->group_flag & G_SEQUENCE)
- X printf(" %4d ", gh->preseq_index);
- X else
- X printf(" ");
- X }
- X
- X printf("%s\n", gh->group_name);
- X }
- X}
- X
- X
- X/*
- X * nntidy
- X */
- X
- Xstatic int
- X tidy_unsubscribed = 0, /* truncate lines for unsub groups*/
- X tidy_remove_unsub = 0, /* remove lines for unsub groups*/
- X tidy_sequence = 0, /* remove groups not in sequence */
- X tidy_ignored = 0, /* remove G_IGN groups */
- X tidy_crap = 0, /* remove unrecognized lines */
- X tidy_all = 0; /* all of the above */
- X
- XOption_Description(tidy_options) {
- X 'N', Bool_Option(no_update),
- X 'Q', Bool_Option(silent),
- X 'v', Bool_Option(verbose),
- X 'a', Bool_Option(tidy_all),
- X 'c', Bool_Option(tidy_crap),
- X 'i', Bool_Option(tidy_ignored),
- X 'r', Bool_Option(tidy_remove_unsub),
- X 's', Bool_Option(tidy_sequence),
- X 'u', Bool_Option(tidy_unsubscribed),
- X '\0',
- X};
- X
- Xopt_nntidy(argc, argv)
- Xint argc;
- Xchar *argv[];
- X{
- X return parse_options(argc, argv, (char *)NULL,
- X tidy_options, " [group]...");
- X}
- X
- Xdo_tidy_newsrc()
- X{
- X register group_header *gh;
- X int changed;
- X char *why;
- X
- X /* visit_rc_file has been called. */
- X
- X keep_rc_backup = 1;
- X bak_suffix = ".tidy";
- X
- X tidy_newsrc = 0;
- X changed = 0;
- X
- X if (tidy_all)
- X tidy_sequence = tidy_ignored = tidy_crap = tidy_unsubscribed = 1;
- X
- X newsrc_update_freq = 9999;
- X
- X Loop_Groups_Newsrc(gh) {
- X if ((gh->master_flag & M_VALID) == 0) {
- X why = "Unknown group: ";
- X goto delete;
- X }
- X if (tidy_sequence && (gh->group_flag & G_SEQUENCE) == 0) {
- X why = "Not in sequence: ";
- X goto delete;
- X }
- X if (tidy_ignored && (gh->master_flag & M_IGNORE_GROUP)) {
- X why = "Ignored group: ";
- X goto delete;
- X }
- X if (tidy_crap && (gh->group_flag & G_FAKED)) {
- X why = "Crap in .newsrc: ";
- X goto delete;
- X }
- X if (tidy_remove_unsub && (gh->group_flag & G_UNSUBSCRIBED)) {
- X if (gh->group_flag & G_FAKED) continue;
- X why = "Unsubscribed: ";
- X goto delete;
- X }
- X
- X if (tidy_unsubscribed && (gh->group_flag & G_UNSUBSCRIBED)) {
- X if (gh->group_flag & G_FAKED) continue;
- X
- X begin_rc_update(gh);
- X gh->last_db_article = 0;
- X end_rc_update(gh);
- X
- X if (gh->newsrc_line != gh->newsrc_orig) {
- X why = "Truncated: ";
- X goto change;
- X }
- X }
- X if (verbose) {
- X why = "Ok: ";
- X goto report;
- X }
- X continue;
- X
- X delete:
- X gh->newsrc_line = NULL;
- X gh->select_line = NULL;
- X
- X change:
- X changed = 1;
- X
- X report:
- X if (!silent) printf("%s%s\n", why, gh->group_name);
- X }
- X
- X if (changed) {
- X newsrc_update_freq = 0;
- X dump_newsrc();
- X dump_select();
- X printf("NOTICE: Original files are saved with %s extention\n", bak_suffix);
- X }
- X}
- X
- X/*
- X * nngoback
- X */
- X
- Xstatic int
- X goback_interact = 0, /* interactive nngoback */
- X goback_days = -1,
- X goback_alsounsub = 0; /* unsubscribed groups also */
- X
- XOption_Description(goback_options) {
- X 'N', Bool_Option(no_update),
- X 'Q', Bool_Option(silent),
- X 'd', Int_Option(goback_days),
- X 'i', Bool_Option(goback_interact),
- X 'u', Bool_Option(goback_alsounsub),
- X 'v', Bool_Option(verbose),
- X '\0',
- X};
- X
- Xopt_nngoback(argc, argvp)
- Xint argc;
- Xchar ***argvp;
- X{
- X int n;
- X
- X n = parse_options(argc, *argvp, (char *)NULL, goback_options,
- X " days [groups]...");
- X
- X if (goback_days < 0) {
- X if (n == 0 || !isdigit((*argvp)[1][0])) {
- X fprintf(stderr, "usage: %s [-NQvi] days [groups]...\n", pname);
- X nn_exit(1);
- X }
- X goback_days = atoi((*argvp)[1]);
- X n--;
- X ++*argvp;
- X }
- X return n;
- X}
- X
- Xdo_goback()
- X{
- X char back_act[FILENAME];
- X FILE *ba;
- X register group_header *gh;
- X int32 count, total;
- X int groups, y;
- X
- X sprintf(back_act, "%s/active.%d", db_directory, goback_days);
- X if ((ba = open_file(back_act, OPEN_READ)) == NULL) {
- X fprintf(stderr, "Cannot go back %d days\n", goback_days);
- X nn_exit(1);
- X }
- X
- X read_active_file(ba, (FILE *)NULL);
- X
- X fclose(ba);
- X
- X /* visit_rc_file has been called. */
- X
- X keep_rc_backup = 1;
- X bak_suffix = ".goback";
- X newsrc_update_freq = 9999;
- X quick_unread_count = 0;
- X total = groups = 0;
- X
- X if (goback_interact) {
- X init_term();
- X raw();
- X }
- X
- X Loop_Groups_Sequence(gh) {
- X if ((gh->master_flag & M_VALID) == 0) continue;
- X if (!goback_alsounsub && (gh->group_flag & G_UNSUBSCRIBED)) continue;
- X
- X add_unread(gh, 1);
- X
- X count = restore_rc(gh, gh->last_a_article);
- X if (count > 0) {
- X if (goback_interact) {
- X printf("%s + %ld ? (y) ", gh->group_name, (long)count); fl;
- X y = yes(0);
- X putchar(CR); putchar(NL);
- X switch (y) {
- X case 1:
- X break;
- X case 0:
- X gh->newsrc_line = gh->newsrc_orig;
- X gh->select_line = gh->select_orig;
- X continue;
- X case -1:
- X if (total > 0) {
- X printf("\nSave changes sofar? (n) "); fl;
- X if (yes(1) <= 0) nn_exit(0);
- X }
- X goto out;
- X }
- X } else
- X if (verbose)
- X printf("%5ld\t%s\n", (long)count, gh->group_name);
- X
- X total += count;
- X groups++;
- X }
- X }
- X
- X out:
- X
- X if (total == 0) {
- X printf("No articles marked\n");
- X return;
- X }
- X
- X flush_newsrc();
- X
- X if (verbose) putchar(NL);
- X if (!silent)
- X printf("%ld article%s marked unread in %d group%s\n",
- X (long)total, plural((long)total),
- X groups, plural((long)groups));
- X}
- X
- X/* fake this for read_active_file */
- X
- Xgroup_header *add_new_group(name)
- Xchar *name;
- X{
- X return NULL;
- X}
- END_OF_FILE
- if test 34671 -ne `wc -c <'newsrc.c'`; then
- echo shar: \"'newsrc.c'\" unpacked with wrong size!
- fi
- # end of 'newsrc.c'
- fi
- if test -f 'sequence.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'sequence.c'\"
- else
- echo shar: Extracting \"'sequence.c'\" \(14489 characters\)
- sed "s/^X//" >'sequence.c' <<'END_OF_FILE'
- X/*
- X * (c) Copyright 1990, Kim Fabricius Storm. All rights reserved.
- X *
- X * Read presentation sequence file
- X */
- X
- X#include "config.h"
- X#include "debug.h"
- X
- Xexport group_header *group_sequence;
- Xexport char *read_mail = NULL;
- Xexport int also_subgroups = 1;
- Xexport int hex_group_args = 0;
- X
- Xstatic int seq_break_enabled = 1; /* !! enabled */
- Xstatic int ignore_done_flag = 0; /* % toggle */
- X
- Xstatic group_header *tail_sequence = NULL;
- Xstatic group_header *final_sequence = NULL;
- X
- Xstatic int gs_more_groups;
- X
- X
- Xonly_folder_args(args)
- Xchar **args;
- X{
- X register char *arg;
- X
- X while (arg = *args++) {
- X if (*arg == '+' || *arg == '~' || *arg == '/') continue;
- X if (file_exist(arg, "fr")) continue;
- X return 0;
- X }
- X return 1;
- X}
- X
- X
- X#define SHOW_NORMAL 0 /* : put this in at current pos */
- X#define SHOW_FIRST 1 /* < : show these groups first */
- X#define SHOW_LAST 2 /* > : show this as late as possible */
- X#define IGNORE_ALWAYS 3 /* ! : ignore these groups completely */
- X#define IGN_UNLESS_RC 4 /* !:X ignore these groups unless in rc */
- X#define IGN_UNLESS_NEW 5 /* !:O ignore these groups unless new */
- X#define IGN_UNL_RC_NEW 6 /* !:U ignore unsubscribed */
- X#define IGN_IF_NEW 7 /* !:N ignore these groups if new */
- X
- X#define SHOW_MODES " <>!-?*"
- X
- Xstatic enter_sequence(mode, gh)
- Xint mode;
- Xgroup_header *gh;
- X{
- X#ifdef SEQ_TEST
- X if (Debug & SEQ_TEST && mode != SHOW_NORMAL)
- X printf("SEQ(%c), %s\n", SHOW_MODES[mode], gh->group_name);
- X#endif
- X
- X if (gh->master_flag & M_IGNORE_GROUP) return 0;
- X if (ignore_done_flag) {
- X if (gh->group_flag & G_SEQUENCE) return 0;
- X } else
- X if (gh->group_flag & G_DONE) return 0;
- X
- X switch (mode) {
- X case IGN_UNLESS_NEW:
- X if ((gh->group_flag & G_NEW) == 0)
- X gh->group_flag |= G_DONE;
- X return 0;
- X
- X case IGN_IF_NEW:
- X if (gh->group_flag & G_NEW)
- X gh->group_flag |= G_DONE;
- X return 0;
- X
- X case IGN_UNL_RC_NEW:
- X if (gh->group_flag & G_NEW) return 0;
- X if (gh->newsrc_line == NULL || (gh->group_flag & G_UNSUBSCRIBED))
- X gh->group_flag |= G_DONE;
- X return 0;
- X
- X case IGN_UNLESS_RC:
- X if (gh->newsrc_line == NULL || (gh->group_flag & (G_UNSUBSCRIBED|G_NEW)))
- X gh->group_flag |= G_DONE;
- X return 0;
- X
- X case IGNORE_ALWAYS:
- X gh->group_flag |= G_DONE;
- X return 0;
- X
- X default:
- X gh->group_flag |= G_DONE;
- X break;
- X }
- X
- X gh->group_flag |= G_SEQUENCE;
- X
- X if (gh->master_flag & M_NO_DIRECTORY)
- X return 0; /* for nntidy -s */
- X
- X switch (mode) {
- X case SHOW_FIRST:
- X if (tail_sequence) {
- X gh->next_group = group_sequence;
- X group_sequence = gh;
- X break;
- X }
- X /* fall thru */
- X
- X case SHOW_NORMAL:
- X if (tail_sequence)
- X tail_sequence->next_group = gh;
- X else
- X group_sequence = gh;
- X tail_sequence = gh;
- X break;
- X
- X case SHOW_LAST:
- X gh->next_group = final_sequence;
- X final_sequence = gh;
- X break;
- X }
- X return 1;
- X}
- X
- X
- Xstatic faked_entry(name, flag)
- Xchar *name;
- Xflag_type flag;
- X{
- X group_header *gh;
- X
- X gh = newobj(group_header, 1);
- X
- X gh->group_name = name;
- X gh->group_flag = flag | G_FAKED;
- X gh->master_flag = 0;
- X
- X /* "invent" an unread article for read_news */
- X gh->last_article = 1;
- X gh->last_db_article = 2;
- X
- X enter_sequence(SHOW_NORMAL, gh);
- X}
- X
- Xstatic end_sequence()
- X{
- X register group_header *gh, *backp;
- X register int seq_ix;
- X
- X if (tail_sequence)
- X tail_sequence->next_group = NULL;
- X
- X /* set up backward pointers */
- X
- X backp = NULL;
- X seq_ix = 0;
- X Loop_Groups_Sequence(gh) {
- X gh->preseq_index = (gh->group_flag & G_UNSUBSCRIBED) ? 0 : ++seq_ix;
- X gh->prev_group = backp;
- X backp = gh;
- X }
- X
- X#ifdef SEQ_DUMP
- X if (Debug & SEQ_DUMP) {
- X for (gh = group_sequence; gh; gh = gh->next_group)
- X printf("%s\t", gh->group_name);
- X putchar(NL);
- X
- X nn_exit(0);
- X }
- X#endif
- X
- X}
- X
- X
- X#ifdef MAIL_READING
- Xstatic mail_check()
- X{
- X static group_header mail_group;
- X struct stat st;
- X
- X if (read_mail == NULL) return;
- X if (stat(read_mail, &st) < 0) return;
- X if (st.st_size == 0 || st.st_mtime < st.st_atime) return;
- X
- X mail_group.group_name = read_mail;
- X gh->group_flag = G_FOLDER | G_MAILBOX | G_FAKED;
- X gh->master_flag = 0;
- X
- X /* "invent" an unread article for read_news */
- X gh->last_article = 1;
- X gh->last_db_article = 2;
- X
- X
- X if (tail_sequence) {
- X mail_group.next_group = group_sequence;
- X group_sequence = mail_group;
- X } else
- X enter_sequence(SHOW_NORMAL, &mail_group);
- X}
- X#endif
- X
- X
- X
- Xstatic visit_presentation_file(directory, seqfile, hook)
- Xchar *directory, *seqfile;
- XFILE *hook;
- X{
- X import int group_name_args;
- X
- X register FILE *sf;
- X register c;
- X register group_header *gh;
- X group_header *mp_group, *get_group_search();
- X char group[FILENAME], *gname;
- X char savefile[FILENAME], *dflt_save, *enter_macro;
- X extern char *parse_enter_macro();
- X register char *gp;
- X int mode, merge_groups;
- X
- X if (gs_more_groups == 0) return 0;
- X
- X if (hook != NULL)
- X sf = hook; /* hook to init file */
- X else
- X if ((sf = open_file(relative(directory, seqfile), OPEN_READ)) == NULL)
- X return 0;
- X
- X#ifdef SEQ_TEST
- X if (Debug & SEQ_TEST)
- X printf("Sequence file %s/%s\n", directory, seqfile);
- X#endif
- X
- X mode = SHOW_NORMAL;
- X savefile[0] = NUL;
- X
- X while (gs_more_groups) {
- X
- X if ((c = getc(sf)) == EOF) break;
- X if (!isascii(c) || isspace(c)) continue;
- X
- X switch (c) {
- X case '!':
- X mode = IGNORE_ALWAYS;
- X if ((c = getc(sf)) == EOF) continue;
- X if (c == '!') {
- X if (seq_break_enabled) {
- X fclose(sf);
- X return 1;
- X }
- X mode = SHOW_NORMAL;
- X continue;
- X }
- X if (c == ':') {
- X if ((c = getc(sf)) == EOF) continue;
- X if (!isascii(c) || isspace(c) || !isupper(c)) continue;
- X switch (c) {
- X case 'O':
- X mode = IGN_UNLESS_NEW;
- X continue;
- X case 'N':
- X mode = IGN_IF_NEW;
- X continue;
- X case 'U':
- X mode = IGN_UNL_RC_NEW;
- X continue;
- X case 'X':
- X mode = IGN_UNLESS_RC;
- X continue;
- X default:
- X /*should give error here*/
- X mode = SHOW_NORMAL;
- X continue;
- X }
- X }
- X ungetc(c, sf);
- X continue;
- X
- X case '<':
- X mode = SHOW_FIRST;
- X continue;
- X
- X case '>':
- X mode = SHOW_LAST;
- X continue;
- X
- X case '%':
- X ignore_done_flag = ! ignore_done_flag;
- X continue;
- X
- X case '@':
- X seq_break_enabled = 0;
- X mode = SHOW_NORMAL;
- X continue;
- X
- X case '#':
- X do c = getc(sf);
- X while (c != EOF && c != NL);
- X mode = SHOW_NORMAL;
- X continue;
- X
- X }
- X
- X gp = group;
- X merge_groups = 0;
- X do {
- X *gp++ = c;
- X if (c == ',') merge_groups = 1;
- X c = getc(sf);
- X } while (c != EOF && isascii(c) && !isspace(c));
- X
- X *gp = NUL;
- X
- X while (c != EOF && (!isascii(c) || isspace(c))) c = getc(sf);
- X if (c == '+' || c == '~' || c == '/') {
- X gp = savefile;
- X if (c == '+') {
- X c = getc(sf);
- X if (c == EOF || (isascii(c) && isspace(c)))
- X goto use_same_savefile;
- X *gp++ = '+';
- X }
- X do {
- X *gp++ = c;
- X c = getc(sf);
- X } while (c != EOF && isascii(c) && !isspace(c));
- X *gp = NUL;
- X dflt_save = savefile[0] ? copy_str(savefile) : NULL;
- X } else
- X dflt_save = NULL;
- X
- X use_same_savefile:
- X while (c != EOF && (!isascii(c) || isspace(c))) c = getc(sf);
- X if (c == '(') {
- X enter_macro = parse_enter_macro(sf, getc(sf));
- X } else {
- X enter_macro = NULL;
- X if (c != EOF) ungetc(c, sf);
- X }
- X
- X mp_group = NULL;
- X for (gp = group; *gp;) {
- X gname = gp;
- X if (merge_groups) {
- X while (*gp && *gp != ',') gp++;
- X if (*gp) *gp++ = NUL;
- X }
- X start_group_search(gname);
- X
- X while (gh = get_group_search()) {
- X if (!enter_sequence(mode, gh)) continue;
- X
- X if (merge_groups && (gh->group_flag & G_UNSUBSCRIBED) == 0) {
- X if (mp_group == NULL) {
- X gh->group_flag |= G_MERGE_HEAD;
- X } else {
- X mp_group->merge_with = gh;
- X gh->group_flag |= G_MERGE_SUB;
- X }
- X mp_group = gh;
- X }
- X
- X if (gh->save_file == NULL) /* not set by "save-files" */
- X gh->save_file = dflt_save;
- X if (gh->enter_macro == NULL) /* not set by "on entry" */
- X gh->enter_macro = enter_macro;
- X }
- X if (!merge_groups) *gp = NUL;
- X }
- X if (merge_groups && mp_group != NULL)
- X mp_group->merge_with = NULL;
- X mode = SHOW_NORMAL;
- X }
- X
- X fclose(sf);
- X return 0;
- X}
- X
- Xparse_save_files(sf)
- Xregister FILE *sf;
- X{
- X register c;
- X register group_header *gh;
- X group_header *get_group_search();
- X char group[FILENAME];
- X char *savefile = NULL;
- X char namebuf[FILENAME];
- X register char *gp;
- X
- X for (;;) {
- X if ((c = getc(sf)) == EOF) break;
- X if (!isascii(c) || isspace(c)) continue;
- X if (c == '#') {
- X do c = getc(sf); while (c != EOF && c != NL);
- X continue;
- X }
- X gp = group;
- X do {
- X *gp++ = c;
- X c = getc(sf);
- X } while (c != EOF && isascii(c) && !isspace(c));
- X *gp = NUL;
- X
- X if (strcmp(group, "end") == 0) break;
- X
- X while (c != EOF && (!isascii(c) || isspace(c))) c = getc(sf);
- X
- X gp = namebuf;
- X do {
- X *gp++ = c;
- X c = getc(sf);
- X } while (c != EOF && isascii(c) && !isspace(c));
- X *gp = NUL;
- X if (namebuf[0] == NUL) break;
- X if (strcmp(namebuf, "+"))
- X savefile = copy_str(namebuf);
- X
- X start_group_search(group);
- X
- X while (gh = get_group_search())
- X gh->save_file = savefile;
- X }
- X}
- X
- Xnamed_group_sequence(groups)
- Xchar **groups;
- X{
- X register group_header *gh;
- X group_header *get_group_search();
- X register char *group;
- X int found, any, errors, gnum;
- X
- X group_sequence = NULL;
- X also_subgroups = 0;
- X
- X any = errors = 0;
- X while (group = *groups++) {
- X
- X if (hex_group_args) {
- X sscanf(group, "%x", &gnum);
- X if (gnum < 0 || gnum >= master.number_of_groups) continue;
- X gh = &active_groups[gnum];
- X if (enter_sequence(SHOW_NORMAL, gh)) any++;
- X continue;
- X }
- X
- X if (gh = lookup(group)) {
- X if (enter_sequence(SHOW_NORMAL, gh)) any++;
- X continue;
- X }
- X
- X if (file_exist(group, "fr")) {
- X faked_entry(group, G_FOLDER);
- X any++;
- X continue;
- X }
- X
- X if (*group == '+' || *group == '~') {
- X char exp_file[FILENAME];
- X group_header fake_group;
- X
- X current_group = &fake_group;
- X fake_group.group_name = group;
- X group_file_name = NULL;
- X if (expand_file_name(exp_file, group, 1) && file_exist(exp_file, "fr")) {
- X faked_entry(copy_str(exp_file), G_FOLDER);
- X any++;
- X continue;
- X }
- X
- X printf("Folder %s not found\n", group); fl;
- X errors++;
- X continue;
- X }
- X
- X found = 0;
- X start_group_search(group);
- X while (gh = get_group_search()) {
- X found++;
- X enter_sequence(SHOW_NORMAL, gh);
- X }
- X
- X if (!found) {
- X printf("Group %s not found\n", group); fl;
- X errors++;
- X } else
- X any++;
- X }
- X
- X end_sequence();
- X
- X if (errors) user_delay(2);
- X
- X return any;
- X}
- X
- XFILE *loc_seq_hook = NULL; /* sequence in local "init" file */
- XFILE *glob_seq_hook = NULL; /* sequence in global "init" file */
- X
- Xnormal_group_sequence()
- X{
- X register group_header *gh;
- X
- X group_sequence = NULL;
- X gs_more_groups = 1;
- X
- X /* visit_p_f returns non-zero if terminated by !! */
- X
- X if (visit_presentation_file(nn_directory, "seq", loc_seq_hook))
- X goto final;
- X
- X if (visit_presentation_file(lib_directory, "sequence", glob_seq_hook))
- X goto final;
- X
- X Loop_Groups_Sorted(gh) {
- X enter_sequence(SHOW_NORMAL, gh);
- X }
- X
- X final:
- X if (final_sequence)
- X if (tail_sequence) {
- X tail_sequence->next_group = final_sequence;
- X tail_sequence = NULL;
- X } else
- X group_sequence = final_sequence;
- X
- X#ifdef MAIL_READING
- X mail_check();
- X#endif
- X
- X end_sequence();
- X}
- X
- X
- X
- Xstatic char *gs_group;
- Xstatic int gs_length, gs_index, gs_mode;
- Xstatic group_header *gs_only_group = NULL;
- X
- X#define GS_PREFIX0 0 /* group (or group*) */
- X#define GS_PREFIX 1 /* group. */
- X#define GS_SUFFIX 2 /* .group */
- X#define GS_INFIX 3 /* .group. */
- X#define GS_NEW_GROUP 4 /* new group */
- X#define GS_ALL 5 /* all / . */
- X#define GS_NEWSRC 6 /* RC */
- X
- Xstart_group_search(group)
- Xchar *group;
- X{
- X char *dot;
- X int last;
- X import group_header *rc_sequence;
- X
- X gs_index = master.number_of_groups; /* loop will fail */
- X
- X if ((last = strlen(group) - 1) < 0) return;
- X if (group[last] == '*')
- X group[last] = NUL;
- X else
- X if (!also_subgroups && (gs_only_group = lookup(group)) != NULL)
- X return;
- X
- X gs_index = 0;
- X gs_more_groups = 0;
- X gs_length = 0;
- X gs_group = NULL;
- X
- X if (strcmp(group, "NEW") == 0) {
- X gs_mode = GS_NEW_GROUP;
- X return;
- X }
- X
- X if (strncmp(group, "RC", 2) == 0) {
- X gs_mode = GS_NEWSRC;
- X gs_only_group = rc_sequence;
- X gs_more_groups = 1; /* we just can't know! */
- X
- X if (group[2] != ':') return;
- X if (isdigit(group[3]))
- X gs_index = atoi(group+3);
- X else {
- X gs_group = group+3;
- X gs_length = strlen(gs_group);
- X }
- X return;
- X }
- X
- X if (strcmp(group, "all") == 0 || strcmp(group, ".") == 0) {
- X gs_mode = GS_ALL;
- X return;
- X }
- X
- X gs_mode = GS_PREFIX0;
- X
- X if (strncmp(group, "all.", 4) == 0) group += 3;
- X
- X if (*group == '.') gs_mode = GS_SUFFIX;
- X
- X if ((dot = strrchr(group, '.')) != NULL && dot != group) {
- X if (dot[1] == NUL || strcmp(dot+1, "all") == 0) {
- X dot[1] = NUL;
- X gs_mode = (gs_mode == GS_SUFFIX) ? GS_INFIX : GS_PREFIX;
- X }
- X }
- X
- X gs_length = strlen(group);
- X gs_group = group;
- X}
- X
- Xgroup_header *get_group_search()
- X{
- X register group_header *gh;
- X register int c, tail;
- X
- X if (gs_mode == GS_NEWSRC) {
- X do {
- X gh = gs_only_group;
- X if (gh == NULL) return NULL;
- X if (gs_index && --gs_index == 0) {
- X gs_only_group = NULL;
- X } else
- X if (gs_group && gh->group_name_length >= gs_length &&
- X strncmp(gh->group_name, gs_group, gs_length) == 0) {
- X gs_only_group = NULL;
- X } else
- X gs_only_group = gh->newsrc_seq;
- X } while ((!ignore_done_flag && (gh->group_flag & G_DONE)) ||
- X (gh->master_flag & M_IGNORE_GROUP));
- X return gh;
- X }
- X
- X if (gs_only_group != NULL) {
- X gh = gs_only_group;
- X gs_only_group = NULL;
- X if (!ignore_done_flag && gh->group_flag & G_DONE) return NULL;
- X if (gh->master_flag & M_IGNORE_GROUP) return NULL;
- X return gh;
- X }
- X
- X while (gs_index < master.number_of_groups) {
- X gh = sorted_groups[gs_index++];
- X if (!ignore_done_flag && gh->group_flag & G_DONE) continue;
- X if (gh->master_flag & M_IGNORE_GROUP) continue;
- X
- X gs_more_groups++;
- X
- X if ((tail = gh->group_name_length - gs_length) < 0) continue;
- X
- X switch (gs_mode) {
- X
- X case GS_NEW_GROUP:
- X if ((gh->group_flag & G_NEW) == 0) continue;
- X break;
- X
- X case GS_PREFIX0:
- X if ((c = (gh->group_name)[gs_length]) != NUL && c != '.') continue;
- X case GS_PREFIX:
- X if (strncmp(gh->group_name, gs_group, gs_length)) continue;
- X break;
- X
- X case GS_SUFFIX:
- X if (strcmp(gh->group_name + tail, gs_group)) continue;
- X break;
- X
- X case GS_INFIX:
- X user_error(".name. notation not supported (yet)");
- X break;
- X
- X case GS_ALL:
- X break;
- X }
- X
- X gs_more_groups--;
- X return gh;
- X }
- X
- X return NULL;
- X}
- END_OF_FILE
- if test 14489 -ne `wc -c <'sequence.c'`; then
- echo shar: \"'sequence.c'\" unpacked with wrong size!
- fi
- # end of 'sequence.c'
- fi
- echo shar: End of archive 5 \(of 22\).
- cp /dev/null ark5isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 22 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
-
- exit 0 # Just in case...
-